package com.xtm.exercise.base.A04string;

import cn.hutool.core.util.StrUtil;
import org.junit.Test;

import java.io.UnsupportedEncodingException;
import java.util.*;

/**
 * String类中常用的方法
 *
 * split()：把字符串分割成字符串数组
 * indexOf()：从指定字符提取索引位置
 * trim()：去除字符串两端空格
 * replace()：替换
 * hashCode()：返回此字符串的哈希码
 * subString()：截取字符串
 * 注意：substr 截取字符串 使用在js和plsql中
 *     1）substr(start,length)表示从start位置开始，截取length长度的字符串。
 *         var src="images/off_1.png";
 *         alert(src.substr(7,3));
 *         弹出值为：off
 *
 *     Oracle  sql 截取字符串
 *     substr(t.minor_code,0,1)   0 代表索引，1 代表截取位置（但不包括最后一位）
 *
 *     2）substr(2);  表示截取从索引2到最后的字符串
 * equals()：比较
 * length()：获取字符串的长度
 * valueOf()：转换为字符串
 * concat()：将指定字符串连接到此字符串的结尾
 * compareTo()：用来比较两个字符串的字典顺序
 * compareToIgnoreCase()：不考虑大小写,按字典顺序比较两个字符串
 * contains()： 检查一个字符串中是否包含想要查找的值
 * charAt() 获取指定索引的字符
 * lastIndexOf()方法返回从右向左出现某个字符或字符串的首个字符索引值（与indexOf相反）
 * equalsIgnoreCase()
 */
public class StringDemo {

    @Test
    public void teest1(){
        if(true || false){
            System.out.println("111");
        }
    }

    /**
     * 把字符串分割成字符串数组
     */
    @Test
    public void split(){
        String str = "a,b,c,d";
        String[] arr = str.split(",");
        System.out.println(arr);

        Long a = 20L;
        boolean equals = a.equals(null);
        System.out.println(equals);

        Long aa = 1200923L;
        String ssss = String.valueOf(aa);
        System.out.println(ssss);
    }

    /**
     * 使用指定连接符连接多个字符串
     * java8 特性
     */
    @Test
    public void join(){
        String[] str = {"a", "b", "c"};
        String join = String.join("-", str);
        System.out.println(join);//a-b-c

        List list = new ArrayList();
        list.add("qw");
        list.add("as");
        list.add("zx");
        String listjosn = String.join("-", list);
        System.out.println("listjosn:" +listjosn);//qw-as-zx

        /////////////////////   普通写法
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < str.length; i++) {
            String s = str[i];
            sb.append(s + "-");
        }
        System.out.println("sb:" +sb.substring(0,sb.length()-1));
    }

    /**
     * 从指定字符提取索引位置 (索引从0开始)
     * indexOf() 方法返回某个指定的字符串值在字符串中首次出现的位置（索引）（从左向右）。没有匹配的则返回-1，否则返回首次出现位置的字符串的下标值。
     */
    @Test
    public void indexOf(){
        String str = "abcd";
        int b = str.indexOf("b");
        int c = str.indexOf("c");
        System.out.println(b);
        System.out.println(c);
    }

    /**
     * 去除字符串两端空格
     */
    @Test
    public void trim(){
        String str = " abcd e";
        System.out.println(str);// abcd
        String trim = str.trim();
        System.out.println(trim);//abcd
    }

    /**
     * 替换
     */
    @Test
    public void replace(){
        String str = "abcd";
        String replace = str.replace('b', 'B');
        System.out.println(replace);
    }

    /**
     * 返回此字符串的哈希码  hashCode
     */
    @Test
    public void hashCode1(){
        String str = "abcd";
        int i = str.hashCode();
        System.out.println(i);
    }

    /**
     * 截取字符串 索引从0开始  substring 从beginIndex开始到endIndex结束
     */
    @Test
    public void subString(){
        String str = "abcd";

        //substring是字符串切割方法，只有一个参数的话就是从这位开始到字符串的终点
        String substring = str.substring(2);
        System.out.println(substring);//cd

        //substring(start,end)表示从start到end之间的字符串，包括start位置的字符但是不包括end位置的字符。
        String substring1 = str.substring(1, 2);
        System.out.println(substring1);//b

        String st = "1020301";
        String s1 = st.substring(0, 2) + "S" + st.substring(2);

        String s2 = st.substring(0, 4) + "S" + st.substring(4);

        String s3 = st + "S";


        System.out.println(st);


    }

    /**
     * 比较  不推荐，null值 会报空指针 ，推荐用 equalsIgnoreCase
     */
    @Test
    public void equals(){
        String str = "abcd";
        boolean abcd = str.equals("abcd");
        System.out.println(abcd);//true

        boolean abc = str.equals("abc");//false
        System.out.println(abc);
    }

    /**
     * 比较
     * 区别：equals()是Object类中定义的方法，判断两个对象是不是“相等”，会区分大小写；equalsIgnoreCase是string类中定义的方法，用来比较两个字符串中对应的字符是否相等，会忽略大小写。
     *
     * 首先看equals()方法，它是判断两个是不是同一个地址的对象，如果是返回true，如果不是，判断这两个对象是不是都是String类的，如果不是，返回false，如果是，那么对两个对象同时进行遍历，比较他们同一位置的字符是否一样，如果都是一样的，返回true，否则返回false;
     * 然后看equalsIgnoreCase()方法，首先也是判断两个是不是同一个地址的对象，如果是，返回true，如果不是，先判断是否不为空和长度是否相等，都为true以后调用regionMatches()方法
     */
    @Test
    public void equalsIgnoreCase(){
//        String str = "abcd";
        String str = null;
        boolean b = "abcd".equalsIgnoreCase(str);  // TODO 开发常用
        System.out.println(b);
    }

    /**
     * 判断两个字符串是否相同，不要用equals , 避免 null 出现空指针
     * 可以用  Objects.equals(s1, s2); 或  StrUtil.equals(s1, s2);
     * @param
     */
    @Test
    public void object(){
//        String s1 = "abc";
        String s1 = null;
        String s2 = "abc";
//        boolean b = s1.equals(s2); // NullPointerException null是不能调用方法的,会抛出空指针异常
//        System.out.println(b);
        /*
            Objects类的equals方法:对两个对象进行比较,防止空指针异常
            public static boolean equals(Object a, Object b) {
                return (a == b) || (a != null && a.equals(b));
            }
         */
        // TODO 开发常用
        boolean b2 = Objects.equals(s1, s2);
        System.out.println(b2);
        boolean equals = StrUtil.equals(s1, s2);
        System.out.println(equals);
    }

    /**
     * 获取字符串的长度
     */
    @Test
    public void length(){
        String str = "abcd";
        int length = str.length();
        System.out.println(length);
    }

    /**
     * 将指定字符串连接到此字符串的结尾
     */
    @Test
    public void concat(){
        String a = "hello";
        String b = "World";
        String concat = a.concat(b);
        System.out.println(concat); //helloWorld
    }

    /**
     * 用来比较两个字符串的字典顺序
     */
    @Test
    public void compareTo(){
        String str1 = "Strings";
        String str2 = "Strings";
        String str3 = "Strings123";

        int result = str1.compareTo( str2 );
        System.out.println(result);

        result = str2.compareTo( str3 );
        System.out.println(result);

        result = str3.compareTo( str1 );
        System.out.println(result);
    }

    /**
     * 不考虑大小写,按字典顺序比较两个字符串
     */
    @Test
    public void compareToIgnoreCase(){
        String str1 = "Strings";
        String str2 = "Strings";
        String str3 = "Strings123";

        int result = str1.compareToIgnoreCase( str2 );
        System.out.println(result);

        result = str2.compareToIgnoreCase( str3 );
        System.out.println(result);

        result = str3.compareToIgnoreCase( str1 );
        System.out.println(result);
    }

    /**
     * 检查一个字符串中是否包含想要查找的值
     */
    @Test
    public void contains(){
        String str = "1234";
        boolean contains = str.contains("2");
        System.out.println(contains);//true
    }

    /**
     * 获取字符串指定位置的字符
     * String 类的charAt()方法返回一个String类对象中某个特定位置的字符
     */
    @Test
    public void charAt(){
        String t = "alibaba";
        char charAt = t.charAt(3);
        System.out.println(charAt);//b
    }

    /**
     * lastIndexOf()方法返回从右向左出现某个字符或字符串的首个字符索引值（与indexOf相反）
     */
    @Test
    public void lastIndexOf(){
        String t = "alibaba";
        int i = t.indexOf("b");
        int y = t.lastIndexOf("b");
        System.out.println(i);//3
        System.out.println(y);//5

        String str = "12.jpg";
        String b = str.substring(str.lastIndexOf(".") + 1);
        System.out.println(b); // 12
    }

    /**
     * deleteCharAt 删除字符串最后一位
     */
    @Test
    public void test11(){
        StringBuilder sb = new StringBuilder();
        String str = "abcdefg";
        sb.append(str);
        //截取最后一位
        sb.deleteCharAt(str.length() - 1);
        System.out.println("删除字符串最后一位:" + sb); //abcdef
    }

    /**
     * 转String类型时，最好用toString()方法
     * 不要用 String 强转
     * String cost = map.get("cost") == null ? null : map.get("cost").toString();
     */
    @Test
    public void test12(){
        HashMap<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("wayss","wayss");

        //使用强转的时候，需要判断一下是否有值
        if (paramsMap.containsKey("wayss")) {
            String wayss = paramsMap.get("wayss").toString();
            if (wayss != null) {
                paramsMap.put("wayss", wayss);
            }
        }

        //简化写法
        if(paramsMap.containsKey("wayss")) {
            String strTag = paramsMap.get("wayss") == null ? "": paramsMap.get("wayss").toString();
        }
    }

    /**
     * 将一个由英文字母组成的字符串转换成指定格式---从右边开始每三个字母用逗号分隔的形式
     */
    @Test
    public void test01(){
        //创建一个空的StringBuilder
        StringBuilder str = new StringBuilder();
        //追加字符串
        str.append("javaeespringboot");
        //从后往前每隔三位插入逗号
        for (int i = str.length()-3;i>0;i=i-3) {
            str.insert(i, ',');//指定位置插入逗号
        }
        //将StringBuilder对象转换成String对象并输出
        System.out.println(str.toString());
    }

    /**
     * 请编写程序，将键盘录入的字符串倒序打印，并测试。
     * 例： 键盘输入:abcde
     *      打印输出:edcba
     */
    @Test
    public void test02(){
        String s = "abcd";
        StringBuffer stringbuffer = new StringBuffer(s);
        stringbuffer.reverse();
        System.out.println(stringbuffer);
    }

    /**
     * 请编写程序，将键盘录入的字符串中敏感字符过滤掉，并测试。
     * 例： 敏感字： 奥巴马、普京
     *  键盘输入: 我喜欢奥巴马呀，还喜欢普京
     *      打印输出: 我喜欢*呀，还喜欢*
     */
    @Test
    public void tst03(){
        String str = "我喜欢奥巴马呀，还喜欢普京";
        String resultStr = stringFilter(str);
        System.out.println(resultStr);
    }
    //将键盘录入的字符串中敏感字符过滤掉
    public static String stringFilter(String str) {
        String[] filters = {"奥巴马","金正恩","普京"};
        for (int i = 0; i < filters.length; i++) {
            String filter = filters[i];
            str = str.replace(filter, "**");
        }
        return str;
    }

    /**
     * 请编写程序，校验键盘录入的用户名是否为正确的格式，并测试。（要求用户名的正确格式长度必须为6-16位数字或字母）
     */
    @Test
    public void test04(){
        // 创建Scanner类
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入用户名");// 提示输入用户名
        String s = sc.nextLine();
        String regex = "[a-zA-Z_1-9][a-zA-Z_0-9]{5,15}";// 6-16位数字或者字母
        boolean matches = s.matches(regex);// 返回Boolean 判断对错
        if (matches == true) {
            System.out.println("格式正确");
        } else if (matches == false) {
            System.out.println("格式错误");
        }
    }

    /**
     * 请编写程序，统计键盘录入的字符串中出现了几次字符串”java”，并测试。例: 键盘输入：woyaoxuejava,xihuanjava,aijava,javajavawozuiai
     */
    @Test
    public void test05(){
        String s1 = "woyaoxuejava,xihuanjava,aijava,javajavawozuiai";
        String s = "java";
        int oldlength = s1.length();//获取老字符串长度
        String s2 = s1.replaceAll("java", "");//用空字符替换java,得到新字符串
        int newlength = s2.length();//得到新字符串长度
        int chalength = oldlength - newlength;
        int count = chalength / s.length();//长度差值/java长度，得到次数
        System.out.println("字符串“java”出现了" + count + "次");
    }

    /**
     * 根据a-z,A-Z 52个字母，写出一个随机获取4位验证码的方法，并进行测试
     *  思路：
     *   1.创建字符数组，通过遍历为数组内每个索引的元素进行赋值
     *   2.在0-52个随机数中，遍历4次，获取新的索引
     *   3.通过新的索引找到字符数组内对应的元素值
     */
    @Test
    public void test06(){
        char[] s=new char[52];    //创建字符数组
        char a1 ='a';
        char a2 ='A';
        for (int i = 0; i <s.length; i++) {
            if (i<26) {
                s[i]=a1;//通过遍历为数组内每个索引的元素进行赋值
                a1++;
            }else{
                s[i]=a2;
                a2++;
            }
        }
        Random rd = new Random();
        for (int i = 0; i < 4; i++) {
            int a=rd.nextInt(52);//在0-52个随机数中，遍历4次，获取新的索引
            char aa=s[a];//通过新的索引找到字符数组内对应的元素值
            System.out.print(aa);
        }
    }

    /**
     * String.getBytes()方法中的中文编码问题
     */
    @Test
    public void test07() throws UnsupportedEncodingException {
        String str = "中";
        //String.getBytes(String decode)方法会根据指定的decode编码返回某字符串在该编码下的byte数组表示
        byte[] a = str.getBytes("UTF-8");
        byte[] b = str.getBytes("GBK");
        byte[] c = str.getBytes("ISO8859-1");
        System.out.println(a.length);
        System.out.println(b.length);
        System.out.println(c.length);
//        而与getBytes相对的,可以通过new String(byte[], decode)的方式来还原这个"中"字,  这个new String(byte[], decode)实际是使用指定的编码decode来将byte[]解析成字符串。
        String s_gbk = new String(a,"GBK");
        String s_utf8 = new String(b,"UTF-8");
        String s_iso88591 = new String(c,"ISO8859-1");
        System.out.println(s_gbk);
        System.out.println(s_utf8);
        System.out.println(s_iso88591);
    }

    /**
     * 三元表达式
     * 格式：
     * 数据类型 变量名称 = 条件判断 ? 表达式A : 表达式B
     *
     * 条件判断 是一个布尔值（true/false）
     *
     * 流程：
     * 首先判断条件是否成立：
     *     如果成立为true,那么将表达式A的值赋值给左侧的变量；
     *     如果成立为false,表达式B进行赋值
     */
    @Test
    public void test08(){
        int a = 1;
        int b = 10;
        int max = a < b ? a : b ;
        System.out.println(max);
    }

    @Test
    public void test13(){
        String str = "Hello";
        String toLowerCase = str.toLowerCase();
        System.out.println(toLowerCase);
        String toUpperCase = toLowerCase.toUpperCase();
        System.out.println(toUpperCase);
    }

    @Test
    public void teset10(){
        //模仿星期几
        String str = "1,2";
        String s = this.conventWeekStrIn(str);
        System.out.println(s);

        String s1 = this.conventWeekStrOut(s);
        System.out.println(s1);
    }

    private String conventWeekStrIn(String str){
        StringBuilder strBuil = new StringBuilder();
        String[] strArr = str.split(",");
        List<String> list = Arrays.asList(strArr);
        for(int i= 1;i<=7;i++){
            if(list.contains(String.valueOf(i))){
                strBuil.append("1");
            }else{
                strBuil.append("0");
            }
        }
        return strBuil.toString();
    }


    private String conventWeekStrOut(String str){
        if("".equals(str)||"null".equals(str)){
            return str;
        }
        StringBuilder afterStr = new StringBuilder();
        for(int i = 1; i<=str.length();i++){
            if('1' == str.charAt(i-1)){
                if(afterStr.length()>0){
                    afterStr.append(",").append(i);
                }else{
                    afterStr.append(i);
                }
            }
        }
        return afterStr.toString();
    }

    @Test
    public void test90(){
        // 如果常量池中存在当前字符串，就会直接返回当前字符串；如果常量池中没有此字符串，会将此字符串放入常量池中后，再返回
        String s = new String("1");
        s.intern();
        String s2 = "1";
        System.out.println(s == s2);

        String s3 = new String("1") + new String("1");
        s3.intern();
        String s4 = "11";
        System.out.println(s3 == s4);
//        创建s3生成了两个最终对象（不考虑两个new String("1")，常量池中也没有“11”），一个是s3，另一个是池中的“1”。
//        如果在1.6中，s3调用intern()方法，则先在常量池中寻找是否有等于“11”的对象，本例中自然是没有，然后会在堆中创建一个“11”的对象，并在常量池中存储它的引用并返回。
//        然而在1.7中调用intern()，如果这个字符串在常量池中是第一次出现，则不会重新创建对象，直接返回它在堆中的引用。
//        在本例中，s4和s3指向的都是在堆中的那个对象，所以s3和s4的地址相等。

    }

}
